package br.com.foxinline.manager.criar;

import br.com.foxinline.enums.Patrimonio;
import br.com.foxinline.modelo.*;
import br.com.foxinline.servico.*;
import br.com.foxinline.util.Conexao;
import br.com.foxinline.util.Msg;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import java.beans.Transient;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.primefaces.event.map.OverlaySelectEvent;
import org.primefaces.event.map.PointSelectEvent;
import org.primefaces.event.map.StateChangeEvent;
import org.primefaces.model.map.DefaultMapModel;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.MapModel;
import org.primefaces.model.map.Marker;
import org.primefaces.model.map.Polygon;
import org.primefaces.model.map.Polyline;

/**
 *
 * @author laverson
 */
@ViewScoped
@ManagedBean
public class ManagerMapaPatrimonio implements Serializable {

    @EJB
    QuadraServico quadraServico;
    @EJB
    CoordenadaServico coordenadaServico;
    @EJB
    BairroServico bairroServico;
    @EJB
    PrefeituraServico prefeituraServico;
    @EJB
    ImovelServico imovelServico;
    @EJB
    AverbacaoServico averbacaoServico;
    private Quadra quadra;
    private MapModel mapModel;
    private Polygon polygon;
    private String centroMapa;
    private int zoomLevelMapa;
    private Polyline polyline;
    private Imovel imovel;
    private boolean connect;

    @PostConstruct
    public void init() {
        this.centroMapa = prefeituraServico.getCentroMapa();
        this.zoomLevelMapa = prefeituraServico.getZoomMapa();

        this.quadra = new Quadra();
        this.quadra.setSetor(new Setor());
        this.mapModel = new DefaultMapModel();
        this.polygon = new Polygon();
        this.imovel = new Imovel();

        if (prefeituraServico.find().getDesabilitarMapas()) {

            this.connect = false;
        } else if (!Conexao.isInternetReachable()) {

            this.connect = false;
            Msg.messagemWarn("Não foi possível estabelecer uma conexão com a Internet.");
        } else {
            this.connect = true;
        }
    }

    public void handlePointClick(PointSelectEvent event) {

        LatLng latLng = event.getLatLng();

        addOverlayToMapModel(new Marker(latLng));

        this.mapModel.addOverlay(this.polygon);

        for (Marker premarker : this.mapModel.getMarkers()) {
            premarker.setDraggable(true);
        }
    }

    private void addOverlayToMapModel(Marker marker) {
        if (marker.getData() == null || !marker.getData().equals(Quadra.class.getSimpleName())) {

            this.mapModel.addOverlay(marker);
            this.polygon.getPaths().add(marker.getLatlng());
            this.polygon.setStrokeColor("#FF9900");
            this.polygon.setFillColor("#FF9900");
            this.polygon.setFillOpacity(0.1);
        }
    }

    public void onStateChange(StateChangeEvent event) {
        this.zoomLevelMapa = event.getZoomLevel();
        this.centroMapa = event.getCenter().getLat() + ", " + event.getCenter().getLng();
    }

    public void onMarkerSelect(OverlaySelectEvent event) {
        try {
            Marker marker = (Marker) event.getOverlay();

            imovel = imovelServico.find((Long) marker.getData());

        } catch (Exception e) {
            System.err.println(e);
        }
    }

    public void mapearSetor() {

        List<Quadra> quadras = quadraServico.find(this.quadra.getSetor());

        this.mapModel = new DefaultMapModel();
        this.quadra.setCoordenadas(coordenadaServico.find(this.quadra));
        List<Coordenada> coordenadas = coordenadaServico.find(this.quadra.getSetor());

        Double lat = 0.0, log = 0.0;

        for (Coordenada c : coordenadas) {
            lat += c.getLat();
            log += c.getLog();
        }

        this.zoomLevelMapa = 15;
        this.centroMapa = lat / coordenadas.size() + ", " + log / coordenadas.size();

        if (!coordenadas.isEmpty()) {

            adicionarPolilyneMapModel(coordenadas, false, null, null);

            for (Quadra q : quadras) {
                adicionarPolilyneMapModel(coordenadaServico.find(q), true, q.getNumero(), null);
            }
        }

        mapearBairros(coordenadas);
    }

    public void mapearBairros(List<Coordenada> coordenadaSetor) {
        try {

            if (coordenadaSetor.size() >= 3) {

                String p1 = construirMatrizPolygon(coordenadaSetor);

                List<Bairro> bairros = bairroServico.findAll();

                for (Bairro bairro : bairros) {

                    if (bairro.getCoordenadas() != null) {

                        List<Coordenada> coordenadasBairro = bairroServico.lstCoordenadaBairro(bairro);

                        if (coordenadasBairro.size() >= 3) {

                            String p2 = construirMatrizPolygon(coordenadasBairro);

                            if (verificarInterseccao(p1, p2)) {
                                mapearBairro(bairro, this.mapModel);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println(e);
            Msg.messagemError(Msg.Failure);
        }
    }

    private String construirMatrizPolygon(List<Coordenada> coordenadas) {
        String p1 = "POLYGON((";
        for (Coordenada gf : coordenadas) {
            if (gf.getLat() != 0) {
                p1 += gf.getLat() + " " + gf.getLog() + ", ";
            }
        }
        p1 += coordenadas.get(0).getLat() + " " + coordenadas.get(0).getLog() + " )) ";

        return p1;
    }

    private Boolean verificarInterseccao(String p1, String p2) {

        try {

            WKTReader reader = new WKTReader(new GeometryFactory());
            com.vividsolutions.jts.geom.Polygon polygon1 = (com.vividsolutions.jts.geom.Polygon) reader.read(p1);
            com.vividsolutions.jts.geom.Polygon polygon2 = (com.vividsolutions.jts.geom.Polygon) reader.read(p2);

            return polygon1.intersects(polygon2);

        } catch (ParseException ex) {
            System.err.println(ex);
        }

        return null;
    }

    public void mapearBairro(Bairro bairro, MapModel mapModel) {
        Polyline polylineBairro = new Polyline();
        LatLng coord;

        List<Coordenada> coordenadasBairro = bairroServico.lstCoordenadaBairro(bairro);

        for (Coordenada c : coordenadasBairro) {
            coord = new LatLng(c.getLat(), c.getLog());

            polylineBairro.getPaths().add(coord);

            polylineBairro.setStrokeColor("#1B93DF");
            polylineBairro.setStrokeWeight(5);
        }

        if (coordenadasBairro != null && !coordenadasBairro.isEmpty()) {
            coord = new LatLng(coordenadasBairro.get(0).getLat(), coordenadasBairro.get(0).getLog());
            polylineBairro.getPaths().add(coord);
        }

        mapModel.addOverlay(polylineBairro);
    }

    public void mapearQuadra() {
        mapearSetor();

        List<Coordenada> coordenadas = coordenadaServico.find(this.quadra.getSetor());

        adicionarPolilyneMapModel(coordenadas, false, null, null);

        List<Imovel> imoveis;
        Imovel imovel = new Imovel();
        Double lat = 0.0, log = 0.0;

        for (Coordenada coordenada : this.quadra.getCoordenadas()) {
            lat += coordenada.getLat();
            log += coordenada.getLog();
        }

        this.zoomLevelMapa = 17;
        this.centroMapa = lat / this.quadra.getCoordenadas().size() + ", " + log / this.quadra.getCoordenadas().size();

        adicionarPolilyneMapModel(coordenadaServico.find(this.quadra), true, this.quadra.getNumero(), null);

        imovel.setInscricaoCadastralQuadra(this.quadra.getNumero());
        imovel.setInscricaoCadastralS(this.quadra.getSetor().getNumero());

        imoveis = imovelServico.find(imovel, null, null);

        for (Imovel i : imoveis) {

            if (i.getCoordenadas() != null && !i.getCoordenadas().isEmpty()) {

                adicionarPolilyneMapModel(i.getCoordenadas(), true, null, i);
            }
        }
    }

    private void adicionarPolilyneMapModel(List<Coordenada> coordenadas, boolean adicionarMarker, Integer numeroQuadra, Object data) {

        if (!coordenadas.isEmpty()) {

            LatLng coord;
            this.polyline = new Polyline();

            Double lat = 0.0, lng = 0.0;

            for (Coordenada c : coordenadas) {
                coord = new LatLng(c.getLat(), c.getLog());

                if (adicionarMarker) {
                    lat += coord.getLat();
                    lng += coord.getLng();
                }

                this.polyline.getPaths().add(coord);
            }

            coord = new LatLng(coordenadas.get(0).getLat(), coordenadas.get(0).getLog());
            this.polyline.getPaths().add(coord);
            this.polyline.setStrokeWeight(2);

            if (!adicionarMarker) {
                this.polyline.setStrokeColor("#ff0000");
            } else {
                this.polyline.setStrokeColor("#1B93DF");
            }

            this.polyline.setStrokeOpacity(0.7);

            this.mapModel.addOverlay(this.polyline);

            if (adicionarMarker) {
                coord = new LatLng(lat / coordenadas.size(), lng / coordenadas.size());

                Marker mk;
                String markerIcon;

                if (numeroQuadra != null) {

                    markerIcon = getRequestURL().concat("/media/images/quadra/quadra_" + numeroQuadra + ".gif");
                    mk = new Marker(coord, "", Quadra.class.getSimpleName(), markerIcon);
                } else {
                    Imovel i = (Imovel) data;

                    if (i.getPatrimonio() == null) {
                        i.setPatrimonio(Patrimonio.PARTICULAR);
                    }

                    markerIcon = getRequestURL().concat("/media/images/marker/imovel/" + i.getPatrimonio().name().toLowerCase() + ".png");

                    mk = new Marker(coord, i.getPatrimonio().getNome(), i.getId(), markerIcon);
                }

                mk.setDraggable(false);
                this.mapModel.addOverlay(mk);
            }
        }
    }

    @Transient
    private String getRequestURL() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        String requestURL = request.getRequestURL().toString();
        String url = requestURL.substring(0, requestURL.lastIndexOf("/"));
        return url;
    }

    public String nomeProprietarios() {
        return averbacaoServico.getNomeProprietarios(this.imovel.getProprietarios());
    }

    public MapModel getMapModel() {
        return mapModel;
    }

    public void setMapModel(DefaultMapModel mapModel) {
        this.mapModel = mapModel;
    }

    public Quadra getQuadra() {
        return quadra;
    }

    public void setQuadra(Quadra quadra) {
        this.quadra = quadra;
    }

    public String getCentroMapa() {
        return centroMapa;
    }

    public void setCentroMapa(String centroMapa) {
        this.centroMapa = centroMapa;
    }

    public int getZoomLevelMapa() {
        return zoomLevelMapa;
    }

    public void setZoomLevelMapa(int zoomLevelMapa) {
        this.zoomLevelMapa = zoomLevelMapa;
    }

    public Imovel getImovel() {
        return imovel;
    }

    public void setImovel(Imovel imovel) {
        this.imovel = imovel;
    }

    public boolean isConnect() {
        return connect;
    }

    public void setConnect(boolean connect) {
        this.connect = connect;
    }
}
